#include <iostream>
#include <string>
#include <cerrno>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

const uint16_t port = 8080;

int main()
{
    // 1、创建套接字，打开文件；返回值本质就是文件描述符
    //  AF_INET表示ipv4；SOCK_DGRAM表示原始套接字类型（常用于UDP）
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
    {
        std::cerr << "socket create erro:" << errno << std::endl;
        return 1;
    }
    // std::cout << "sock:" << sock << std::endl; // 3

    // 2、给服务器绑定端口和ip
    struct sockaddr_in local;
    local.sin_family = AF_INET;
    //此处的端口号是我们计算机上的变量，是主机序列
    local.sin_port = htons(port);
    //将点分十进制IP地址转化成为4字节整数IP，同时需要考虑大小端
    //通过 in_addr_t inet_addr(const char *cp);能满足上面的要求
    //云服务器不允许用户bind公网IP
    // local.sin_addr.s_addr = inet_addr("1.12.53.79");
    //如果bind的是确定的IP，意味着只有发到该IP主机上面的数据
    //但是一般服务器可能有多张网卡，配置多个IP
    //我们需要的不是某个IP上面的数据，需要的是发送到该主机端口的任意数据
    local.sin_addr.s_addr = INADDR_ANY;

    if (bind(sock, (struct sockaddr *)&local, sizeof(local)) < 0)
    {
        std::cerr << "bind error:" << errno << std::endl;
        return 2;
    }

    // 3、提供服务
    bool quit = false;
#define NUM 1024
    char buffer[NUM];
    while (!quit)
    {
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        //读取客户端发送过来的消息消息
        recvfrom(sock, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len);
        //打印读取到的信息
        std::cout << "client#:" << buffer << std::endl;
        //回显给客户端一条消息
        std::string echo_hello = "heelo!";
        sendto(sock, echo_hello.c_str(), echo_hello.size(), 0, (struct sockaddr *)&peer, len);
    }

    return 0;
}